/**
 * Copyright (c) 2010-2019 Data.Co.Ltd. All rights reserved.
 */
package info.peigen.hotpot.component.gateway.core.mock;

import com.google.common.collect.Lists;
import info.peigen.hotpot.common.core.result.ListResult;
import info.peigen.hotpot.common.core.result.ResultCode;
import info.peigen.hotpot.common.core.result.SingleResult;
import info.peigen.hotpot.common.service.base.gateway.AbstractGatewayRequest;
import info.peigen.hotpot.common.service.base.test.mock.ServiceTestMockContext;
import info.peigen.hotpot.common.service.base.test.mock.ServiceTestMockContextThreadLocal;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

import static info.peigen.hotpot.common.core.result.ResultCode.*;

/**
 * <b>(AbstractGatewayBase)</b>
 * 网关基类
 * 新增加支持的网关必须继承自GatewayBase
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2019-05-28
 */
@Slf4j
public abstract class AbstractMockGateway implements MockConstant {

    protected void queryMock(MockServiceContext context, HandleQueryMock handleQueryMock) {
        ServiceTestMockContext mockContext = ServiceTestMockContextThreadLocal.currentContext();
        if (FAILURE == mockContext.getExpectResultCode()) {
            context.setFail(concatDetail(mockContext.getExpectErrorCode(), mockContext.getExpectErrorDesc()));
            return;
        }

        if (CHANNEL_TIMEOUT == handleQueryMock.handleTimeoutException()) {
            context.setTimeout();
            return;
        }

        if (INTERNAL_ERROR == handleQueryMock.handleException()) {
            context.setFail();
            return;
        }

        if (PARAMETER_ERROR == handleQueryMock.handleException()) {
            context.setFailByCode(PARAMETER_ERROR);
            return;
        }

        handleQueryMock.handleSuccess(context);
    }

    protected void transMock(MockServiceContext context, HandleTransMock handleTransMock) {
        ServiceTestMockContext mockContext = ServiceTestMockContextThreadLocal.currentContext();
        if (FAILURE == mockContext.getExpectResultCode()) {
            context.setFail(concatDetail(mockContext.getExpectErrorCode(), mockContext.getExpectErrorDesc()));
            return;
        }

        if (PROCESSING == handleTransMock.handleProcessing(context)) {
            context.setProcessing();
            return;
        }

        if (CHANNEL_TIMEOUT == handleTransMock.handleTimeoutException()) {
            context.setTimeout();
            return;
        }

        if (INTERNAL_ERROR == handleTransMock.handleException()) {
            context.setFail();
            return;
        }

        handleTransMock.handleSuccess(context);
    }

    protected String concatDetail(String transRejectCode, String transStatusDescription) {
        return "渠道返回:code=" + transRejectCode + ",desc=" + transStatusDescription;
    }

    protected boolean isTimeout(String... timeoutStrs) {
        return Arrays.stream(timeoutStrs).anyMatch(str -> isTimeout(str));
    }

    protected boolean isFailure(String... failureStrs) {
        return Arrays.stream(failureStrs).anyMatch(str -> isFailure(str));
    }

    protected boolean isFailure(String failureStr) {
        return isFailure(Lists.newArrayList(failureStr));
    }

    protected boolean isFailure(List<String> failureStrs) {
        List<String> allFailure = Lists.newArrayList();
        allFailure.addAll(BANKCARD_NO_FAILURE);
        allFailure.addAll(ID_NO_FAILURE);
        return failureStrs.stream().anyMatch(str -> allFailure.contains(str));
    }

    protected boolean isNotSuccess(String notSuccessStr) {
        return isNotSuccess(Lists.newArrayList(notSuccessStr));
    }

    protected boolean isNotSuccess(List<String> notSuccessStrs) {
        List<String> allSuccess = Lists.newArrayList();
        allSuccess.addAll(BANKCARD_NO_SUCCESS);
        allSuccess.addAll(ID_NO_SUCCESS);
        return notSuccessStrs.stream().anyMatch(str -> !allSuccess.contains(str));
    }

    protected boolean isTimeout(String timeoutStrs) {
        return isTimeout(Lists.newArrayList(timeoutStrs));
    }

    protected boolean isTimeout(List<String> timeoutStrs) {
        List<String> timeouts = Lists.newArrayList();
        timeouts.addAll(BANKCARD_NO_TIME_OUT);
        timeouts.addAll(ID_NO_TIME_OUT);
        return timeoutStrs.stream().anyMatch(str -> timeouts.contains(str));
    }

    public void callForSingleGateway(AbstractGatewayRequest requestBase, SingleResult result) {
        result.setInternalError(ResultCode.INTERFACE_NOT_REALIZE.message());
    }

    public void callForBatchGateway(AbstractGatewayRequest requestBase, ListResult result) {
        result.setInternalError(ResultCode.INTERFACE_NOT_REALIZE.message());
    }

    /** 查询Mock */
    public interface HandleQueryMock {

        /**
         * 成功用例处理
         *
         * @param context Mock上下文
         */
        void handleSuccess(MockServiceContext context);

        /**
         * 失败用例处理
         *
         * @param context Mock上下文
         *
         * @return 返回值
         */
        default ResultCode handleFailure(MockServiceContext context) {
            return UNKNOWN;
        }

        /**
         * 超时异常处理
         *
         * @return 返回值
         */
        default ResultCode handleTimeoutException() {
            return UNKNOWN;
        }

        /**
         * 其他异常处理
         *
         * @return 返回值
         */
        default ResultCode handleException() {
            return UNKNOWN;
        }

    }

    /** 交易Mock */
    public interface HandleTransMock {

        /**
         * 成功用例处理
         *
         * @param context Mock上下文
         */
        void handleSuccess(MockServiceContext context);

        /**
         * 处理中用例处理
         *
         * @param context Mock上下文
         *
         * @return 返回值
         */
        default ResultCode handleProcessing(MockServiceContext context) {
            return UNKNOWN;
        }

        /**
         * 超时异常处理
         *
         * @return 返回值
         */
        default ResultCode handleTimeoutException() {
            return UNKNOWN;
        }

        /**
         * 其他异常处理
         *
         * @return 返回值
         */
        default ResultCode handleException() {
            return UNKNOWN;
        }
    }
}